package com.adcc.monitoragent.core.service;

import java.lang.management.ManagementFactory;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.hyperic.sigar.CpuPerc;
import org.hyperic.sigar.FileSystem;
import org.hyperic.sigar.FileSystemUsage;
import org.hyperic.sigar.Mem;
import org.hyperic.sigar.NetInterfaceConfig;
import org.hyperic.sigar.NetInterfaceStat;
import org.hyperic.sigar.OperatingSystem;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.Swap;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adcc.monitoragent.bean.OsBean;
import com.adcc.monitoragent.bean.OsBean.Disk;
import com.adcc.monitoragent.bean.OsBean.Net;
import com.adcc.monitoragent.log.ServiceLogger;
import com.adcc.monitoragent.send.MessageSend;
import com.adcc.monitoragent.util.Constants;
import com.adcc.monitoragent.util.ProtertiesUtil;

/**
 * ip 唯一确定
 * 操作系统监控，内存，CPU，线程
 * 
 * @author charlie
 * 
 */
@PersistJobDataAfterExecution   
@DisallowConcurrentExecution
public class OsService implements Job {
	private final static Logger log = LoggerFactory.getLogger(OsService.class);
	private static MBeanServer mBeanServer = ManagementFactory
			.getPlatformMBeanServer();
	private static DecimalFormat df = new DecimalFormat("##############.##");
	private static Sigar sigar = null;
	private static OsBean lastOsBean;

	/**
	 * 获取内存信息
	 * @param sigar
	 * @param os
	 */
	private static void memory(Sigar sigar, OsBean os) {
		 try {
			Mem mem = sigar.getMem();  
		    Swap swap = sigar.getSwap();  
		    
		    os.setOsMemoryTotal(df.format((mem.getTotal()/(1024D*1024D*1024D))) + "G");
			//e.g. linux
	        if ((mem.getUsed() != mem.getActualUsed()) ||
	            (mem.getFree() != mem.getActualFree())) {
	        	os.setOsMemoryFree(df.format((mem.getActualFree()/(1024D*1024D*1024D))) + "G");
	        	os.setOsMemoryUsePercent(df.format(mem.getActualUsed() * 100/mem.getTotal() ) + "%");
	        } else {
	        	os.setOsMemoryFree(df.format((mem.getFree()/(1024D*1024D*1024D))) + "G");
	        	os.setOsMemoryUsePercent(df.format(mem.getUsed() * 100/mem.getTotal() ) + "%");
	        }
	        os.setOsSwapTotal(df.format((swap.getTotal()/(1024D*1024D*1024D))) + "G");
			os.setOsSwapFree(df.format((swap.getFree()/(1024D*1024D*1024D))) + "G");
			os.setOsSwapUsePercent(df.format(swap.getUsed() * 100/swap.getTotal()) + "%");
		} catch (SigarException e) {
			log.error("获取内存信息失败" + e.getMessage());
		} 
	}
	
	/**
	 * 获取cpu使用信息
	 * @param sigar
	 * @param os
	 */
	private static void cpu(Sigar sigar, OsBean os) {  
        try {
        	os.setOsProcessors(sigar.getCpuInfoList().length + "");
        	os.setOsCpuRatio(CpuPerc.format(sigar.getCpuPerc().getUser()));
		} catch (SigarException e) {
			log.error("cpu信息获取失败" + e.getMessage());
		}  
    }
	
	/**
	 * 系统信息
	 * @param sigar
	 * @param os
	 */
	private static void os(Sigar sigar, OsBean os) {  
	        try {
				OperatingSystem opers = OperatingSystem.getInstance();  
				os.setOsArch(opers.getArch());
				os.setOsName(opers.getVendorName());
			} catch (Exception e) {
				log.error("系统信息获取失败" + e.getMessage());
			}
	}  
	
	private static void file(Sigar sigar, OsBean os) {  
        try {
			FileSystem fslist[] = sigar.getFileSystemList();  
			List<Disk> osDiskList =  new ArrayList<Disk>();
			for (int i = 0; i < fslist.length; i++) { 
				FileSystem fs = fslist[i];
				Disk d = new Disk();
				d.setName(fs.getDevName());
				d.setPath(fs.getDirName());
				d.setType(fs.getSysTypeName());
				
			    FileSystemUsage usage;
				try {
					usage = sigar.getFileSystemUsage(fs.getDirName());
				} catch (Exception e) {
					//异常盘符跳过
					continue;
				}  
			    switch (fs.getType()) {  
			        case 2: // TYPE_LOCAL_DISK : 本地硬盘  
			            // 文件系统资源的利用率  
			            double usePercent = usage.getUsePercent() * 100D;  
			            d.setTotal(usage.getTotal() / (1024 * 1024) + "G");
			        	d.setFree(usage.getFree() / (1024 * 1024) + "G");
			        	d.setUsePercent(df.format(usePercent) + "%");
			            break;  
			        default:
			            break;  
			    } 
			    //过滤无用磁盘
			    if(null == d.getTotal() || "0G".equals(d.getTotal())) {
			    	continue;
			    }
			    d.setReads(usage.getDiskReads() + "");
				d.setWrites(usage.getDiskWrites() + "");
				osDiskList.add(d);
			}  
			os.setOsDiskList(osDiskList);
		} catch (SigarException e) {
			log.error("磁盘信息获取失败" + e.getMessage());
		}
    }  
	
	/**
	 * 网络信息 
	 * @throws Exception
	 */
    private static void net(Sigar sigar, OsBean os) { 
    	//转换成map
    	Map<String, Net> netMap = new HashMap<String, Net>();
    	if(lastOsBean != null) {
	    	List<Net> netList = lastOsBean.getOsNetList();
	    	for (Net net : netList) {
	    		netMap.put(net.getMac(), net);
			}
    	}
    	Set<String> set =  new HashSet<String>();
        try {
			String ifNames[] = sigar.getNetInterfaceList();  
			List<Net> osNetList = new ArrayList<Net>();
			for (int i = 0; i < ifNames.length; i++) {  
				String name = ifNames[i];  
				NetInterfaceConfig ifconfig = sigar.getNetInterfaceConfig(name);  
				if ((ifconfig.getFlags() & 1L) <= 0L) {  
			        continue;  
			    }  
			    if (ifconfig.getHwaddr() == null || "00:00:00:00:00:00".equals(ifconfig.getHwaddr())) {  
			        continue;  
			    } 
			    NetInterfaceStat ifstat = sigar.getNetInterfaceStat(name);  
				Net n = new Net();
				n.setMac(ifconfig.getHwaddr().toUpperCase());
				if(set.contains(n.getMac()) || ifstat.getRxPackets() <= 0
						|| ifstat.getTxPackets() <= 0) {
					continue;
				} else {
					set.add(n.getMac());
				}
				Net oldN = netMap.get(n.getMac());
				long rxPacketsPer = 0;
				long txPacketsPer = 0;
				long rxDataPer = 0;
				long txDataPer = 0;
				if(oldN != null) {
					rxPacketsPer = (ifstat.getRxPackets() - Long.parseLong(oldN.getRxPackets()));
					txPacketsPer = (ifstat.getTxPackets() - Long.parseLong(oldN.getTxPackets()));
					rxDataPer = (ifstat.getRxBytes()/(1024) - Long.parseLong(oldN.getRxData()));
					txDataPer = (ifstat.getTxBytes()/(1024) - Long.parseLong(oldN.getTxData()));
				}
				
				n.setRxPackets(ifstat.getRxPackets() + "");
				n.setRxPacketsPer(rxPacketsPer + "");
				n.setTxPackets(ifstat.getTxPackets() + "");
				n.setTxPacketsPer(txPacketsPer + "");
				n.setRxData(ifstat.getRxBytes()/(1024) + "");//K
				n.setRxDataPer(rxDataPer + "");
				n.setTxData(ifstat.getTxBytes()/(1024) + "");//K
				n.setTxDataPer(txDataPer + "");
				n.setRxErrors(ifstat.getRxErrors() + "");
				n.setTxErrors(ifstat.getTxErrors() + "");
				n.setRxDropped(ifstat.getRxDropped() + "");
				n.setTxDropped(ifstat.getTxDropped() + "");
				osNetList.add(n);
			}
			os.setOsNetList(osNetList);
		} catch (SigarException e) {
			log.error("网络信息获取失败" + e.getMessage());
		}  
    }  
    /**
     * 计算最大打开文件数
     * @return
     */
    private static void maxFdLimit(OsBean osBean) {
		String s = "";
		try {
			if (System.getProperty("os.name").toLowerCase()
					.startsWith("windows")) {
				s = "";
			} else {
				s = mBeanServer.getAttribute(new ObjectName(
						"java.lang:type=OperatingSystem"),
						"MaxFileDescriptorCount").toString();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		osBean.setOsFdMax(s);
	}
	
	public static OsBean getInfo(String ip) {
		if(sigar == null ) {
			sigar = new Sigar();
		}
		
		OsBean osBean = new OsBean();
		osBean.setIp(ip);
		osBean.setStatus(Constants.STATUS_OK);
		try {
			memory(sigar, osBean);
			cpu(sigar, osBean);
			os(sigar, osBean);
			file(sigar, osBean);
			net(sigar, osBean);
			//设置系统最大文件数
			maxFdLimit(osBean);
			//计算系统是否正常
			double cpu = Double.parseDouble(osBean.getOsCpuRatio().replace("%", ""));
			double memory = Double.parseDouble(osBean.getOsMemoryUsePercent().replace("%", ""));
			if(cpu >= 95 || memory >= 95) {
				osBean.setStatus(Constants.STATUS_ERROR);
			}
			for (Disk disk : osBean.getOsDiskList()) {
				double di = Double.parseDouble(disk.getUsePercent().replace("%", ""));
				if(di >= 95) {
					osBean.setStatus(Constants.STATUS_ERROR);
				}
			}
		} catch (Exception e) {
			log.error("OS信息获取失败" + e.getMessage());
		}
		return osBean;
	}
	
	@Override
	public void execute(JobExecutionContext arg0) throws JobExecutionException {
		log.debug("定时执行任务。。。。。。。。。。。。");
		OsBean bean = OsService.getInfo(ProtertiesUtil.getOsIp());
		boolean statusChange = lastOsBean != null && !lastOsBean.getStatus().equals(bean.getStatus());
		if(bean.getStatus().equals(Constants.STATUS_ERROR) && statusChange) {//如果状态异常 并且 状态改变
			log.warn("Os状态正常转异常，休眠2秒重试，防止误判");
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
			}
			bean = OsService.getInfo(ProtertiesUtil.getOsIp());
			if(bean.getStatus().equals(Constants.STATUS_ERROR)) {//状态还是异常
				String desc = "异常";
				ServiceLogger.error(bean.getIp(), null, "os", desc);
			}
		} else if(statusChange){//状态由异常转正常
			String desc = "正常";
			ServiceLogger.info(bean.getIp(), null, "os", desc);
		}
		lastOsBean = bean;
		//转发消息
		MessageSend.sendMsg(bean);
		log.debug("完成任务。。。。。。。。。。。。");
	}
	
	public static void main(String[] args) throws Exception {
		System.setProperty("java.library.path", System.getProperty("user.dir"));
		while(true) {
			OsBean bean = OsService.getInfo("192.168.243.16");
			System.out.println(bean);
			Thread.sleep(5000);
		}
	}
}
